package com.office.tools.wps;


import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.office.config.wps.ConvertInfo;
import com.office.office.wps.ConstantsWPS;
import com.office.office.wps.dto.FileConvertResult;
import com.office.office.wps.dto.RequestBody;
import com.office.office.wps.dto.TaskQueryResult;
import com.office.tools.OfficeResult;
import org.apache.http.HttpEntity;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Map;
import java.util.Set;

/*
 * @BelongsProject: office
 * @BelongsPackage: com.office.tools.wps
 * @Author: TongHui
 * @CreateTime: 2024-03-13 09:56
 * @Description: TODO
 * @Version: 1.0
 */
public class SDKUtil {

    private Logger logger = LoggerFactory.getLogger(SDKUtil.class);

    private static SDKUtil sdkUtil = null;
    private String DOMAIN_NAME ; // 中台地址
    private String AK ;          // 应用 id
    private String SK ;          // 密钥


    private SDKUtil(){}
    private SDKUtil(String domainName,String ak,String sk){
        this.DOMAIN_NAME = domainName;
        this.AK = ak;
        this.SK = sk;
    }
    public static SDKUtil create(String domainName,String ak,String sk){
        if (sdkUtil == null){
            sdkUtil = new SDKUtil(domainName, ak, sk);
        }
        return sdkUtil;
    }

    // ======================字体信息查询======================
    public FileConvertResult fontsQuery(RequestBody requestBody){
        String json =  JSONUtil.toJsonStr(requestBody);
        //请求头
        WPS4Signature signature = new WPS4Signature(AK, SK);
        Map<String, String> headers = signature.getSignatureHeaders("GET", ConstantsWPS.API_FONTS_QUERY, json, new Date(), ConstantsWPS.CONTENT_TYPE);

        String url = DOMAIN_NAME + ConstantsWPS.API_FONTS_QUERY;
        logger.info("WPS中台URL："+url);
        OfficeResult<String> result = post(url, json, headers);
        return JSONUtil.toBean(result.getData(), FileConvertResult.class);
    }

    // ======================任务查询======================

    public TaskQueryResult taskQuery(String taskId,String routeKey){
        String url =  ConstantsWPS.API_TASK_QUERY_ASYNC + taskId;
        //请求头
        WPS4Signature signature = new WPS4Signature(AK, SK);
        Map<String, String> headers = signature.getSignatureHeaders("GET", url, "", new Date(), ConstantsWPS.CONTENT_TYPE);
        headers.put("Route-Key", routeKey);

         url = DOMAIN_NAME + url;
        logger.info("WPS中台URL："+url);

        OfficeResult<String> result = get(url, headers);
        return JSONUtil.toBean(result.getData(), TaskQueryResult.class);
    }


    //======================文件下载=================================

    /*
     *
     * @param download_id  wps返回值
     * @param route_key    wps返回值
     * @return
     */
    public byte[] fileDownload(String download_id,String route_key){
        //请求头
        WPS4Signature signature = new WPS4Signature(AK, SK);
        Map<String, String> headers = signature.getSignatureHeaders("GET", ConstantsWPS.API_DOWNLOAD+download_id, "", new Date(), ConstantsWPS.CONTENT_TYPE);
        headers.put("Route-Key", route_key);

        String url = DOMAIN_NAME + ConstantsWPS.API_DOWNLOAD+download_id;
        logger.info("WPS中台URL："+url);
        return fileDownloadGet(url,headers);
    }

    //===========================文件转换===============================

    public byte[] fileConvert_sync(ConvertInfo convertInfo){
        String json = JSONUtil.toJsonStr(convertInfo);
        //请求头
        WPS4Signature signature = new WPS4Signature(AK, SK);
        Map<String, String> headers = signature.getSignatureHeaders("POST",ConstantsWPS.API_CONVERT_SYNC, json, new Date(), ConstantsWPS.CONTENT_TYPE);

        String url = DOMAIN_NAME + ConstantsWPS.API_CONVERT_SYNC;
        logger.info("WPS中台URL："+url);

        OfficeResult result = post(url,json, headers);

        FileConvertResult convertResult = JSONUtil.toBean((String) result.getData(), FileConvertResult.class);

        return fileDownload(convertResult.getDownload_id(),convertResult.getRoute_key());
    }

    public FileConvertResult fileConvert_async(ConvertInfo convertInfo){
        String json = JSONUtil.toJsonStr(convertInfo);
        //请求头
        WPS4Signature signature = new WPS4Signature(AK, SK);
        Map<String, String> headers = signature.getSignatureHeaders("POST",ConstantsWPS.API_CONVERT_ASYNC, json, new Date(), ConstantsWPS.CONTENT_TYPE);

        String url = DOMAIN_NAME + ConstantsWPS.API_CONVERT_ASYNC;
        logger.info("WPS中台URL："+url);

        OfficeResult<String> result = post(url,json, headers);

        return JSONUtil.toBean(result.getData(), FileConvertResult.class);
    }

    //===================================文件预览=================================================
    public  OfficeResult getPreviewURl(String fileId,String fileName){
        return getPreviewURl(fileId, fileName,null,null,null);
    }
    public  OfficeResult getPreviewURl(String fileId,String fileName,PreviewMode previewMode,String wpsPreview,Integer _w_tokentype){
        return getPreviewURl(fileId, fileName, previewMode,wpsPreview, _w_tokentype,null);
    }

    /**
     * 请求文件预览路径
     * @param fileId      文件id
     * @param fileName      文件id
     * @param _w_tokentype 是否验证token
     * @param params 自定义参数  appid 、file_id 字段已被使用，
     *
     * @param previewMode 预览模式
     * @param wpsPreview 高清预览支持控制修订痕迹、评论是否显示等参数。 览参数wpsPreview=1111111从左到右依次代表：
     *             第0位：格式修订：0不显示；1：显示
     *             第1位：插入和删除：0不显示；1：显示
     *             第2位：评论 0不显示；1：显示
     *             第3位：以嵌入模式显示修订
     *             第4位：以气泡模式显示修订
     *             第5位：0不显示标记；1：显示标记
     *             第6位：0最终状态；1：原始状态
     * 注：(第3、4位组合：01及11为批注框方式；10是嵌入方式
     * 00是批注框显示修订者)
     * @return 返回结果
     */
    public  OfficeResult getPreviewURl(String fileId,String fileName,PreviewMode previewMode,String wpsPreview,Integer _w_tokentype,Map<String,String> params){
        String type = WPSFileTypeUtil.openPreview(fileName);
        String url =  ConstantsWPS.API_PREVIEW.replace("${file_id}",fileId)+"?type="+type;

        // 是否传token到回调接口
        if (null != _w_tokentype && _w_tokentype.equals(1)){
            url += "&_w_tokentype="+_w_tokentype;
        }
        //预览模式
        if (null != previewMode){
            url += "&preview_mode="+previewMode;
        }
        //高清预览控制
        if (null != wpsPreview){
            url += "&wpsPreview="+wpsPreview;
        }

        // 组合请求路径
        if (null != params && params.size() > 0){
            Set<String> keySet = params.keySet();
            String[] keyArr = new String[keySet.size()];
            int i = 0;
            for (String key : keySet) {
                String value = params.get(key);
                try {
                    keyArr[i] = ConstantsWPS.PREFIX+key+"="+ URLEncoder.encode(value, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                i++;
            }
            url += "&" + String.join("&",keyArr);
        }

        //请求头
        WPS4Signature signature = new WPS4Signature(AK, SK);
        Map<String, String> headers = signature.getSignatureHeaders("GET",url, "", new Date(), ConstantsWPS.CONTENT_TYPE);

        url = DOMAIN_NAME + url;
        logger.info("WPS中台URL："+url);

        OfficeResult<String> OfficeResult = get(url, headers);
        return OfficeResult;
    }

    //==========================文件编辑======================================
    public  OfficeResult getEditURl(String fileId,String fileName){
        return getEditURl(fileId,fileName,null);
    }
    public  OfficeResult getEditURl(String fileId,String fileName,Integer _w_tokentype){
        return getEditURl(fileId,fileName,_w_tokentype,null);
    }

    /**
     *
     * @param fileId        文件id
     * @param fileName      文件名称
     * @param _w_tokentype  是否传token
     * @param params        自定义参数  appid 、file_id 字段已被使用，
     * @return 返回结果
     */
    public  OfficeResult getEditURl(String fileId,String fileName,Integer _w_tokentype,Map<String,String> params){
        String type = WPSFileTypeUtil.openEdit(fileName);
        String url =  ConstantsWPS.API_EDIT.replace("${file_id}",fileId)+"?type="+type;

        // 是否传token到回调接口
        if (null != _w_tokentype && _w_tokentype.equals(1)){
            url = url+"&_w_tokentype="+_w_tokentype;
        }
        // 组合请求路径
        if (null != params && params.size() > 0){
            Set<String> keySet = params.keySet();
            String[] keyArr = new String[keySet.size()];
            int i = 0;
            for (String key : keySet) {
                String value = params.get(key);
                try {
                    keyArr[i] = ConstantsWPS.PREFIX+key+"="+URLEncoder.encode(value, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                i++;
            }
            url += "&" + String.join("&",keyArr);
        }

        //请求头
        WPS4Signature signature = new WPS4Signature(AK, SK);
        Map<String, String> headers = signature.getSignatureHeaders("GET",url, "", new Date(), ConstantsWPS.CONTENT_TYPE);

        url = DOMAIN_NAME + url;
        logger.info("WPS中台URL："+url);

        OfficeResult OfficeResult = get(url, headers);
        logger.info("文件编辑URL："+OfficeResult.getData());
        return OfficeResult;
    }


    private byte[] fileDownloadGet(String url, Map<String, String> headers){
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        ByteArrayOutputStream outputStream = null;
        try {
            httpClient = wrapClient();
            // 创建POST请求
            HttpGet httpGet = new HttpGet(url);
            if (null != headers) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    httpGet.addHeader(entry.getKey(), entry.getValue());
                }
            }
            // 发送请求并获取响应
            response = httpClient.execute(httpGet);

            outputStream = new ByteArrayOutputStream();
            response.getEntity().writeTo(outputStream);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                outputStream.close();
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return outputStream.toByteArray();
    }

    private OfficeResult<String> get(String url, Map<String, String> headers){
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        String responseBody = "";
        try {
            httpClient = wrapClient();

            // 创建Get请求
            HttpGet httpGet = new HttpGet(url);
            if (null != headers) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    logger.info(entry.getKey() + "=" + entry.getValue());
                    httpGet.addHeader(entry.getKey(), entry.getValue());
                }
            }

            // 发送请求并获取响应
            response = httpClient.execute(httpGet);

            // 打印响应
            System.out.println("Response Code: " + response.getStatusLine().getStatusCode());
            HttpEntity entity = response.getEntity();
            responseBody = EntityUtils.toString(entity);
            System.out.println("Response Body: " + responseBody);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        int code = response.getStatusLine().getStatusCode();
        JSONObject jsonObject = JSONUtil.toBean(responseBody, JSONObject.class);

        return getOfficeResult(code,jsonObject);
    }


    private OfficeResult<String> post(String url, String json, Map<String, String> headers){

        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        String responseBody = "";
        try {

            httpClient = wrapClient();

            // 创建POST请求
            HttpPost httpPost = new HttpPost(url);
            if (null != headers) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    logger.info(entry.getKey() + "=" + entry.getValue());
                    httpPost.addHeader(entry.getKey(), entry.getValue());
                }
            }

            // 将 JSON 参数放入请求体，并设置编码为 UTF-8
            HttpEntity httpEntity = EntityBuilder.create()
                    .setContentType(ContentType.APPLICATION_JSON)
                    .setText(json)
                    .setContentEncoding(StandardCharsets.UTF_8.name())
                    .build();

            // 设置请求体（JSON Payload）
            httpPost.setEntity(httpEntity);

            // 发送请求并获取响应
            response = httpClient.execute(httpPost);

            // 打印响应
            System.out.println("Response Code: " + response.getStatusLine().getStatusCode());
            HttpEntity entity = response.getEntity();
            responseBody = EntityUtils.toString(entity);
            System.out.println("Response Body: " + responseBody);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        int code = response.getStatusLine().getStatusCode();
        JSONObject jsonObject = JSONUtil.toBean(responseBody, JSONObject.class);

        return getOfficeResult(code,jsonObject);
    }

    private OfficeResult<String> filePost(String url, byte[] bytes,String fileName, Map<String, Object> params) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        String responseBody = "";

        try {

            httpClient = wrapClient();
            // 创建POST请求
            HttpPost httpPost = new HttpPost(url);
//            httpPost.setHeader("Content-Type", "multipart/form-data");

            MultipartEntityBuilder builder = MultipartEntityBuilder.create();

            builder.addBinaryBody("file", bytes,ContentType.MULTIPART_FORM_DATA,fileName);

            if (params != null) {
                for (String key : params.keySet()) {
                    builder.addTextBody(key, String.valueOf(params.get(key)), ContentType.APPLICATION_JSON);
                }
            }

            HttpEntity reqEntity = builder.build();
            httpPost.setEntity(reqEntity);

            // 发起请求 并返回请求的响应
            response = httpClient.execute(httpPost);
            // 打印响应
            System.out.println("Response Code: " + response.getStatusLine().getStatusCode());
            HttpEntity entity = response.getEntity();
            responseBody = EntityUtils.toString(entity);
            System.out.println("Response Body: " + responseBody);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        int code = response.getStatusLine().getStatusCode();
        JSONObject jsonObject = JSONUtil.toBean(responseBody, JSONObject.class);

        return getOfficeResult(code,jsonObject);
    }

    private OfficeResult<String> getOfficeResult(int code , JSONObject jsonObject){
        OfficeResult<String> officeResult = null;
        if (code == 200 && jsonObject.getInt("code") == 200){
            officeResult = new OfficeResult(code, jsonObject.getStr("msg"));
            officeResult.setCode(jsonObject.getInt("code"));
            officeResult.setData(jsonObject.getStr("data"));
            return officeResult;
        }else {
            code = jsonObject.getInt("code");
            String msg = ErrorCode.getValueByCode(code);
            if (code == 40007){
                msg = jsonObject.getStr("hint");
            }
            throw new IllegalStateException(code+"=="+msg);
        }
    }

    //信任所有SSL证书
    //绕过ssl证书验证
    private CloseableHttpClient wrapClient() {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager trustManager = new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                }
            };
            ctx.init(null, new TrustManager[]{trustManager}, null);
            SSLConnectionSocketFactory ssf = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
            return HttpClients.custom()
                    .setSSLSocketFactory(ssf)
                    .build();
        } catch (Exception e) {
            return HttpClients.createDefault();
        }
    }



}
